package com.triple.interviewexpert.sentinel;

import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.triple.interviewexpert.common.BaseResponse;
import com.triple.interviewexpert.common.ErrorCode;
import com.triple.interviewexpert.common.ResultUtils;
import com.triple.interviewexpert.exception.ThrowUtils;
import com.triple.interviewexpert.model.dto.question.QuestionQueryRequest;
import com.triple.interviewexpert.model.dto.questionBank.QuestionBankQueryRequest;
import com.triple.interviewexpert.model.dto.user.UserLoginRequest;
import com.triple.interviewexpert.model.dto.user.UserRegisterRequest;
import com.triple.interviewexpert.model.vo.LoginUserVO;
import com.triple.interviewexpert.model.vo.QuestionBankVO;
import com.triple.interviewexpert.model.vo.QuestionVO;
import org.springframework.web.bind.annotation.RequestBody;

import javax.servlet.http.HttpServletRequest;

public class SentinelHandler {

    /**
     * listQuestionBankVOByPage 流控操作
     * 限流：提示"系统压力过大，请耐心等待"
     * 熔断：执行降级操作
     */
    public static BaseResponse<Page<QuestionBankVO>> handleListQuestionBankVOByPageBlockException(
            QuestionBankQueryRequest questionBankQueryRequest,
            HttpServletRequest request,
            BlockException ex) {
        // 熔断之后为了阻塞方法执行, 也会进入当前方法
        // 触发降级操作
        if (ex instanceof DegradeException) {
            return handleListQuestionBankVOByPageFallback(questionBankQueryRequest, request, ex);
        }
        // 限流操作
        return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "系统压力过大，请耐心等待");
    }

    /**
     * listQuestionBankVOByPage 降级操作：直接返回本地数据 或 空数据
     */
    public static BaseResponse<Page<QuestionBankVO>> handleListQuestionBankVOByPageFallback(
            QuestionBankQueryRequest questionBankQueryRequest,
            HttpServletRequest request,
            Throwable ex) {
        // 可以返回本地数据或空数据
        return ResultUtils.success(null);
    }

    /**
     * listQuestionVOByPage 流控操作
     * 业务异常：上报并提示"系统错误，业务异常"
     * 限流：提示"访问过于频繁，请稍后再试"
     * 熔断：执行降级操作
     */
    public static BaseResponse<Page<QuestionVO>> handleListQuestionVOByPageBlockException(
            QuestionQueryRequest questionQueryRequest,
            HttpServletRequest request,
            Throwable ex) {
        // 业务异常
        if (!BlockException.isBlockException(ex)) {
            Tracer.trace(ex); // 上报sentinel
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "系统错误，业务异常");
        }
        // 降级操作
        if (ex instanceof DegradeException) {
            return handleListQuestionVOByPageFallback(questionQueryRequest, request, ex);
        }
        // 限流操作
        return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "访问过于频繁，请稍后再试");
    }

    /**
     * listQuestionVOByPage 降级操作：直接返回本地数据 或 空数据
     */
    public static BaseResponse<Page<QuestionVO>> handleListQuestionVOByPageFallback(
            QuestionQueryRequest questionQueryRequest,
            HttpServletRequest request,
            Throwable ex) {
        // 可以返回本地数据或空数据
        return ResultUtils.success(null);
    }

    /**
     * searchQuestionVOByPage 流控操作
     * 业务异常：上报并提示"系统错误，业务异常"
     * 限流：提示"题目搜索过于频繁，请稍后再试"
     * 熔断：执行降级操作
     */
    public static BaseResponse<Page<QuestionVO>> handleSearchQuestionVOByPageBlockException(
            QuestionQueryRequest questionQueryRequest,
            HttpServletRequest request,
            Throwable ex) {
        // 业务异常
        if (!BlockException.isBlockException(ex)) {
            Tracer.trace(ex); // 上报sentinel
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "系统错误，业务异常");
        }
        // 降级操作
        if (ex instanceof DegradeException) {
            return handleSearchQuestionVOByPageFallback(questionQueryRequest, request, ex);
        }
        // 限流操作
        return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "题目搜索过于频繁，请稍后再试");
    }

    /**
     * searchQuestionVOByPage 降级操作：直接返回本地数据 或 空数据
     */
    private static BaseResponse<Page<QuestionVO>> handleSearchQuestionVOByPageFallback(
            QuestionQueryRequest questionQueryRequest,
            HttpServletRequest request,
            Throwable ex) {
        // 可以返回本地数据或空数据
        return ResultUtils.success(null);
    }

    /**
     * userRegister 流控操作
     * 业务异常：上报并提示"系统错误，业务异常"
     * 限流：提示"题目搜索过于频繁，请稍后再试"
     * 熔断：执行降级操作
     */
    public static BaseResponse<Long> handleUserRegisterBlockException(
            UserRegisterRequest userRegisterRequest,
            HttpServletRequest request,
            Throwable ex) {
        // 业务异常
        if (!BlockException.isBlockException(ex)) {
            Tracer.trace(ex); // 上报sentinel
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "系统错误，业务异常");
        }
        // 降级操作
        if (ex instanceof DegradeException) {
            return handleUserRegisterFallback(userRegisterRequest, request, ex);
        }
        // 限流操作
        return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "用户注册过于频繁，请稍后再试");
    }

    /**
     * userRegister 降级操作：返回错误提示
     */
    private static BaseResponse<Long> handleUserRegisterFallback(
            UserRegisterRequest userRegisterRequest,
            HttpServletRequest request,
            Throwable ex) {
        return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "用户注册服务暂时不可用，请稍后再试");
    }

    /**
     * userLogin 流控操作
     * 业务异常：上报并提示"系统错误，业务异常"
     * 限流：提示"题目搜索过于频繁，请稍后再试"
     * 熔断：执行降级操作
     */
    public static BaseResponse<LoginUserVO> handleUserLoginBlockException(
            UserLoginRequest userLoginRequest,
            HttpServletRequest request,
            Throwable ex) {
        // 业务异常
        if (!BlockException.isBlockException(ex)) {
            Tracer.trace(ex); // 上报sentinel
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "登录失败，请检查用户名和密码");
        }
        // 降级操作
        if (ex instanceof DegradeException) {
            return handleUserLoginFallback(userLoginRequest, request, ex);
        }
        // 限流操作
        return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "用户登录过于频繁，请稍后再试");
    }

    /**
     * userLogin 降级操作：返回错误提示
     */
    private static BaseResponse<LoginUserVO> handleUserLoginFallback(
            UserLoginRequest userLoginRequest,
            HttpServletRequest request,
            Throwable ex) {
        return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "用户登录服务暂时不可用，请稍后再试");
    }
}
